<?php
/**
 * CRMLite Captcha Class
 *
 * @final
 * @package     Crmlite_Captcha
 * @version     $Id: Captcha.php 47 2007-09-04 14:11:49Z etng2004 $
 * @copyright   2006-2007 ETE.CN
 * @author      Yi BO  <etng2004@gmail.com>
 * @license     PHP Version 3.0 {@link http://www.php.net/license/3_0.txt}
 */
class Crmlite_Captcha
{
    /**
     * 数字类型验证码
     *
     */
    const CAPTCHA_TYPE_NUM = 0;
    /**
     * 字母类型验证码
     *
     */
    const CAPTCHA_TYPE_ALPHABET = 1;
    /**
     * 16 进制数字转成字母类型验证码
     *
     */
    const CAPTCHA_TYPE_HEX2CHAR = 2;
    /**
     * 混合验证码
     *
     */
    const CAPTCHA_TYPE_MIXED = 3;

    protected $config = array(
    'paddingLeft'   => 3,
    'paddingRight'  => 3,
    'paddingTop'    => 2,
    'paddingBottom' => 2,
    'border'        => 1,
    'color'         => '0xffffff',
    'bgcolor'       => '0x666666',
    'borderColor'   => '0x000000',
    'font'          => 5,
    'length'        => 4,
    'type'          => self::CAPTCHA_TYPE_HEX2CHAR,
    'imagetype'     => IMAGETYPE_GIF,
    'debug'         => false,
    );

    /**
     * 利用 GD 库产生验证码图像
     *
     * 目前 $options 参数支持下列选项：
     * -  paddingLeft, paddingRight, paddingTop, paddingBottom
     * -  border, borderColor
     * -  font, color, bgcolor
     *
     * 如果 font 为 0-5，则使用 GD 库内置的字体。
     * 如果要指定字体文件，则 font 选项必须为字体文件的绝对路径，例如：
     * <code>
     * $options = array('font' => '/var/www/example/myfont.gdf');
     * </code>
     *
     * @param array $options 附加选项，可以指定字体、宽度和高度等参数
     */
    public function __construct(array $config = array())
    {
        function_exists('imagecreate') || die('GD2 extension not found.');
        $this->config = array_merge($this->config, $config);
        $this->loadFont();
    }

    public function getCode($length = 4 , $type = self::CAPTCHA_TYPE_HEX2CHAR)
    {
        switch ($type)
        {
            case self::CAPTCHA_TYPE_NUM:
                $seed = '0123456789';
                break;
            case self::CAPTCHA_TYPE_ALPHABET:
                $seed = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
                break;
            case self::CAPTCHA_TYPE_HEX2CHAR:
                $seed = '';
                foreach (range(0, 15) as $i)$seed .= dechex($i);
                break;
            case self::CAPTCHA_TYPE_MIXED:
            default:
                $seed = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
        }
        $length || $length = 4;

        $this->length = $length;
        $this->type = $type;


        $code = '';
        list($usec, $sec) = explode(" ", microtime());
        srand($sec + $usec * 100000);
        $len = strlen($seed) - 1;
        for ($i = 0; $i < $length; $i++)
        {
            $code .= substr($seed, rand(0, $len), 1);
        }
        $this->code = $code;
        return $code;
    }

    protected function loadFont()
    {
        $font = $this->font;
        if (is_int($font))
        {
            $font = (int)$font;
            if ($font < 0 || $font > 5) { $font = 5; }
        }
        else
        {
            $font_file = dirname(__FILE__) . '/Catptcha/Font/' . $font;
            if(file_exists($font))
            {
                $font = imageloadfont($font);
            }
        }
        $this->font = $font;
    }
    public function __set($key, $val)
    {
        $this->config[$key] = $val;
    }
    public function __get($key)
    {
    	if(array_key_exists($key, $this->config))
    	{
    	    return $this->config[$key];
    	}
    	return false;
    }
    /**
     * 输出生成的验证图像
     *
     */
    public function show()
    {
        extract($this->config, EXTR_SKIP);
        // 确定字体宽度和高度
        $fontWidth  = imagefontwidth($font);
        $fontHeight = imagefontheight($font);

        // 确定图像的宽度和高度
        $width  = $fontWidth * strlen($code) + $paddingLeft + $paddingRight + $border * 2 + 1;
        $height = $fontHeight + $paddingTop + $paddingBottom + $border * 2 + 1;

        // 创建图像
        $img = imagecreate($width, $height);

        // 绘制边框
        if ($border)
        {
            list($r, $g, $b) = $this->_hex2rgb($borderColor);
            $borderColor = imagecolorallocate($img, $r, $g, $b);
            imagefilledrectangle($img, 0, 0, $width, $height, $borderColor);
        }

        // 绘制背景
        list($r, $g, $b) = $this->_hex2rgb($bgcolor);
        $backgroundColor = imagecolorallocate($img, $r, $g, $b);
        imagefilledrectangle($img, $border, $border, $width - $border - 1, $height - $border - 1, $backgroundColor);

        // 绘制文字
        list($r, $g, $b) = $this->_hex2rgb($color);
        $textColor = imagecolorallocate($img, $r, $g, $b);
        imagestring($img, $font, $paddingLeft + $border, $paddingTop + $border, $code, $textColor);
        if($this->debug)header("Captcha:{$code}");
        // 输出图像
        switch (strtolower($this->imagetype)) {
            case IMAGETYPE_PNG:
                header("Content-type: " . image_type_to_mime_type(IMAGETYPE_PNG));
                imagepng($img);
                break;
            case IMAGETYPE_GIF:
                header("Content-type: " . image_type_to_mime_type(IMAGETYPE_GIF));
                header("Content-Disposition: inline; filename=captcha.gif");
                header('Content-Length: ' . strlen($img));
                imagegif($img);
                break;
            case IMAGETYPE_JPEG:
            default:
                header("Content-type: " . image_type_to_mime_type(IMAGETYPE_JPEG));
                imagejpeg($img);
        }

        imagedestroy($img);
        unset($img);
        exit();
    }

    /**
     * 将 16 进制颜色值转换为 rgb 值
     *
     * @param string $hex
     *
     * @return array
     */
    function _hex2rgb($color, $defualt = 'ffffff')
    {
        $color = strtolower($color);
        if (substr($color, 0, 2) == '0x')
        {
            $color = substr($color, 2);
        }
        elseif (substr($color, 0, 1) == '#')
        {
            $color = substr($color, 1);
        }
        $l = strlen($color);
        if ($l == 3)
        {
            $r = hexdec(substr($color, 0, 1));
            $g = hexdec(substr($color, 1, 1));
            $b = hexdec(substr($color, 2, 1));
            return array($r, $g, $b);
        }
        elseif ($l != 6)
        {
            $color = $defualt;
        }

        $r = hexdec(substr($color, 0, 2));
        $g = hexdec(substr($color, 2, 2));
        $b = hexdec(substr($color, 4, 2));
        return array($r, $g, $b);
    }
}
